using System.Collections.Generic;

namespace LS.UnityExtensions
{
    /// <summary>
    /// 二值映射表,支持反向映射
    /// </summary>
    public class DoubleValueMap<TKey,TValue1,TValue2>
    {
        private Dictionary<TKey, TValue1> m_KeyV1Map;
        private Dictionary<TKey, TValue2> m_KeyV2Map;
        private Dictionary<TValue1, TKey> m_V1KeyMap;
        private Dictionary<TValue2, TKey> m_V2KeyMap;

        private bool m_DoubleWay = false;

        /// <summary>
        /// 是否支持双向映射,双向映射时可通过value反向获取其key值
        /// </summary>
        public bool IsDoubleWayMap
        {
            get
            {
                return m_DoubleWay;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="doubleWay">双向映射</param>
        public DoubleValueMap(bool doubleWay = false)
        {
            m_DoubleWay = doubleWay;

            m_KeyV1Map = new Dictionary<TKey, TValue1>();
            m_KeyV2Map = new Dictionary<TKey, TValue2>();

            if (doubleWay)
            {
                m_V1KeyMap = new Dictionary<TValue1, TKey>();
                m_V2KeyMap = new Dictionary<TValue2, TKey>();
            }
        }

        /// <summary>
        /// 设置键值映射
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value1">值</param>
        public void SetValue1Map(TKey key, TValue1 value1)
        {
            m_KeyV1Map[key] = value1;

            if (!m_DoubleWay)
                return;
            
            if (m_KeyV1Map.TryGetValue(key, out TValue1 previous))
            {
                m_V1KeyMap.Remove(previous);
            }
            m_V1KeyMap[value1] = key;
        }

        /// <summary>
        /// 设置键值映射
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value1">值</param>
        public void SetValue2Map(TKey key, TValue2 value2)
        {
            m_KeyV2Map[key] = value2;

            if (!m_DoubleWay)
                return;

            if (m_KeyV2Map.TryGetValue(key, out TValue2 previous))
            {
                m_V2KeyMap.Remove(previous);
            }
            
            m_V2KeyMap[value2] = key;
        }

        /// <summary>
        /// 移除键值映射
        /// </summary>
        /// <param name="key"></param>
        public void RemoveValue1Map(TKey key)
        {
            if (m_DoubleWay)
            {
                if (m_KeyV1Map.TryGetValue(key, out TValue1 previous))
                {
                    m_V1KeyMap.Remove(previous);
                }
            }
            m_KeyV1Map.Remove(key);
        }

        /// <summary>
        /// 移除键值映射
        /// </summary>
        /// <param name="key"></param>
        public void RemoveValue2Map(TKey key)
        {
            if (m_DoubleWay)
            {
                if (m_KeyV2Map.TryGetValue(key, out TValue2 previous))
                {
                    m_V2KeyMap.Remove(previous);
                }
            }
            m_KeyV2Map.Remove(key);
        }

        /// <summary>
        /// 获取值
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public TValue1 GetValue1(TKey key)
        {
            return m_KeyV1Map[key];
        }

        /// <summary>
        /// 通过值获取键，只能在IsDoubleWayMap为True时使用
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public TKey GetKeyByValue1(TValue1 value)
        {
            if (!m_DoubleWay)
            {
                throw new System.Exception("This function is only used in DoubleWay mode");
            }

            return m_V1KeyMap[value];
        }

        /// <summary>
        /// 获取值
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public TValue2 GetValue2(TKey key)
        {
            return m_KeyV2Map[key];
        }

        /// <summary>
        /// 通过值获取键，只能在IsDoubleWayMap为True时使用
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public TKey GetKeyByValue2(TValue2 value)
        {
            if (!m_DoubleWay)
            {
                throw new System.Exception("This function is only used in DoubleWay mode");
            }

            return m_V2KeyMap[value];
        }

        /// <summary>
        /// 清除全部映射
        /// </summary>
        public void Clear()
        {
            m_KeyV1Map?.Clear();
            m_KeyV2Map?.Clear();
            m_V1KeyMap?.Clear();
            m_V2KeyMap?.Clear();
        }
    }
}
